#ifndef T_BOX_PLAYER_H
#define T_BOX_PLAYER_H

#include "t_av_common.h"
#include "t_av_packet.h"
#include "misc.h"
#include <QtCore>

struct T_Box_Stream_Info
{
    bool isValid;
    int stream_index;
    AVCodecContext *codec_ctx;
    AVCodec *codec;
    AVStream *stream;
    T_AV_Packet_Queue packet_queue;
    explicit T_Box_Stream_Info(AVFormatContext *a_format_ctx, AVMediaType a_media_type)
        : isValid(false)
        , stream_index(-1)
        , codec_ctx(0)
        , codec(0)
        , stream(0)
    {
        Q_ASSERT(a_format_ctx);
        Q_ASSERT(a_media_type==CODEC_TYPE_AUDIO || a_media_type==CODEC_TYPE_VIDEO);
        QString v_media_type_str = a_media_type==CODEC_TYPE_AUDIO ? "audio" : "video";
        this->stream_index=-1;
        for(unsigned int i=0; i<a_format_ctx->nb_streams; i++)
            if(a_format_ctx->streams[i]->codec->codec_type==a_media_type)
            {
                this->stream_index=i;
                break;
            }
        if(this->stream_index<0)
        {
            qDebug() << QString("No %1 stream.").arg(v_media_type_str);
            this->isValid = false;
        }
        else
        {
            qDebug()<< QString("m_%1.stream.stream_index]").arg(v_media_type_str)
                    << this->stream_index;
            this->isValid = true;
            this->stream = a_format_ctx->streams[this->stream_index];
            this->codec_ctx=this->stream->codec;
            if(a_media_type==CODEC_TYPE_AUDIO)
            {
                if (this->codec_ctx->channels > 0)
                    this->codec_ctx->request_channels = FFMIN(2, this->codec_ctx->channels);
                else
                    this->codec_ctx->request_channels = 2;
            }
            this->codec=avcodec_find_decoder(this->codec_ctx->codec_id);
            if(!this->codec)
            {
                qDebug() << QString("Unsupported %1 codec.").arg(v_media_type_str);
                this->isValid = false;
            }
            else  if(avcodec_open(this->codec_ctx, this->codec)<0)
            {
                qDebug() << QString("avcodec_open (%1) failed.").arg(v_media_type_str);
                this->isValid = false;
            }
        }
    }
};

class T_Box_Player_Context : public QObject
{
    Q_OBJECT
public:
    AVFormatContext *m_format_ctx;
    T_Box_Stream_Info m_audio;
    T_Box_Stream_Info m_video;
    ////QTime m_time_line;
    T_StopWatch m_time_line;
    DECLARE_ALIGNED(16,quint8,m_audio_decode_array)[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
    DECLARE_ALIGNED(16,quint8,m_audio_convert_array)[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
    explicit T_Box_Player_Context(AVFormatContext *a_format_ctx)
        : m_format_ctx(a_format_ctx)
        , m_audio(m_format_ctx, CODEC_TYPE_AUDIO)
        , m_video(m_format_ctx, CODEC_TYPE_VIDEO)
    {
        qDebug() << "[m_video.isValid]" << m_video.isValid;
        qDebug() << "[m_audio.isValid]" << m_audio.isValid;
    }
    ~T_Box_Player_Context()
    {
        if(m_audio.codec_ctx) avcodec_close(m_audio.codec_ctx);
        if(m_video.codec_ctx) avcodec_close(m_video.codec_ctx);
        if(m_format_ctx) av_close_input_file(m_format_ctx);
    }

    T_AV_Packet *readPacket()
    {
        AVPacket v_av_packet;
        if(::av_read_frame(m_format_ctx, &v_av_packet)<0)
        {
            return NULL;
        }
        T_AV_Packet *v_obj_packet = new T_AV_Packet(this, v_av_packet);
        return v_obj_packet;
    }
    T_AV_Packet *enqueuePacket()
    {
        T_AV_Packet *v_av_packet;
        while((v_av_packet = this->readPacket()))
        {
            if(v_av_packet->m_stream_index==this->m_video.stream_index)
            {
                this->m_video.packet_queue.enqueue(v_av_packet);
                return v_av_packet;
            }
            else if(v_av_packet->m_stream_index==this->m_audio.stream_index)
            {
                this->m_audio.packet_queue.enqueue(v_av_packet);
                return v_av_packet;
            }
            else
            {
                delete v_av_packet;
            }
        }
        return NULL;
    }
};

#endif // T_BOX_PLAYER_H
